using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ItProject.Andir.Cryptography;
using EMISecurity.SymmetricCryptography.CryptoManaged;

namespace Gameshield
{
    public struct ActivationCode
    {
        public uint hwid;
        public uint authid;
        public uint extraData;
        public uint shelfLife;
    }

    public struct AuthRequestCode
    {
        public uint authid;
        public uint hwid;
    }

    public class GameshieldKeyMaker
    {
        Haval256 haval = new Haval256(HavalPassCount.Pass5);
        BlowfishECB blowfish = new BlowfishECB();

        public AuthRequestCode decryptARCFromString(String strARC, String Password)
        {
            strARC = strARC.Replace("-", "");
            UInt64 parsedValue = UInt64.Parse(strARC, System.Globalization.NumberStyles.HexNumber);
            byte[] ACData = BitConverter.GetBytes(parsedValue);

            byte[] decryptData = decryptBlock(ACData,Password);

            UInt64 decryptedValue = BitConverter.ToUInt64(decryptData, 0);

            AuthRequestCode arc = new AuthRequestCode();

            arc.hwid = (uint)decryptedValue & 0x3FFFFFF;
            arc.authid = (UInt32)decryptedValue >> 26;

            return arc;
        }
        public String MakeAC(AuthRequestCode arc, uint extraData, uint shelfLife, String GlobalPassword, String LocalPassword)
        {
            if (shelfLife == 0)
                shelfLife = 0x0880;

            UInt64 acValue = new UInt64();
            UInt64 tmp = new UInt64();

            acValue |= arc.hwid;

            tmp = extraData;
            tmp <<= 26;
            acValue |= tmp;

            tmp = shelfLife;
            tmp <<= 42;
            acValue |= tmp;

            byte[] hash = makeCryptKey(LocalPassword);

            UInt64 xorVal = BitConverter.ToUInt64(hash, 0);

            acValue ^= xorVal;

            acValue <<= 6;
            acValue >>= 6;

            tmp = (ulong)arc.authid << 58;
            acValue |= tmp;

            byte[] encrypted = encryptBlock(BitConverter.GetBytes(acValue), GlobalPassword);

            acValue = BitConverter.ToUInt64(encrypted, 0);

            String ret = acValue.ToString("X16");
            for (int x = 0; x < 3; x++)
            {
                ret = ret.Insert((x + 1) * 4 + x, "-");
            }
            return ret;
        }

        private byte[] decryptBlock(byte[] encryptedData, String password)
        {
            byte[] hash = makeCryptKey(password);

            BlowfishECB blowfish = new BlowfishECB();
            blowfish.Initialize(hash, 0, hash.Length);

            byte[] decryptData = new byte[8];
            blowfish.Decrypt(encryptedData, 0, decryptData, 0, 8);
            return decryptData;
        }

        private byte[] encryptBlock(byte[] data, String password)
        {
            byte[] hash = makeCryptKey(password);

            blowfish.Initialize(hash, 0, hash.Length);

            byte[] encrypted = new byte[8];

            blowfish.Encrypt(data, 0, encrypted, 0, 8);
            return encrypted;
        }

        private byte[] makeCryptKey(String s)
        {
            haval.Initialize();
            byte[] hash = haval.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(s));
            return hash;
        }
    }
}
